﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ContactManagement.Models;
using EFDataModel;
using EFDataModel.Enums;
using Common.Extensions;

namespace ContactManagement.AppCode.CategoryManagement
{
    /// <summary>
    /// Verarbeiten der Benutzergruppen wie Hinzufügen, Bearbeiten oder Löschen
    /// </summary>
    public class WebUserGroups : CategoryBase
    {
        #region Static
        /// <summary>
        /// Singleton Pattern für die aktuelle WebUserGroups
        /// </summary>
        /// <param name="controller">Der Aktuelle Controller</param>
        /// <returns>Instanz der aktuellen WebUserGroups</returns>
        public static WebUserGroups UserGroups(Controller controller)
        {
            return new WebUserGroups(controller);
        }
        #endregion

        #region Member
        /// <summary>
        /// Der Aktuelle Controller, damit auch auf die Tempdaten und alles notwendige zugegriffen werden kann
        /// </summary>
        protected override sealed Controller CurrentController { get; set; }
        #endregion

        #region Konstruktor
        /// <summary>
        /// Initialisieren der WebUserKategorien
        /// </summary>
        /// <param name="controller"></param>
        public WebUserGroups(Controller controller)
        {
            CurrentController = controller;
        }
        #endregion

        #region Public Functions
        /// <summary>
        /// Hinzufügen eines Eintrages zur Kategorie
        /// </summary>
        /// <param name="model"></param>
        /// <returns>TRUE->Erfolgreich angelegt | FALSE->Fehler beim Löschen</returns>
        public override bool Add(CategoriesAddModel model)
        {
            try
            {
                //Erstellen einer neuen UserGruppe
                UserGroup userGroup = new UserGroup();
                userGroup.IsSystem = false;
                userGroup.Name = model.Name;
                userGroup.SortId = model.SortId;
                userGroup.EFCategoryType = EFCategoryTypes.UserCategory;
                CurrentHttpContext.GetDataModel().EFCategoryMenge.Add(userGroup);
                CurrentHttpContext.GetDataModel().SaveChanges();
            }
            catch (Exception)
            {
                //Fehler Beim Anlegen des Eintrags
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.AddValueErrorRESX, MessageTypes.error);
                return false;
            }

            //Der Eintrag konnte erfolgreich angelegt werden
            CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.AddValueSuccessfullRESX, MessageTypes.ok);
            return true;
        }

        /// <summary>
        /// Löschen der übergebenen Kategorie Id
        /// </summary>
        /// <param name="id">die Kategorie Id die gelöscht werden soll</param>
        /// <returns>TRUE->Erfolgreich gelöscht | FALSE->Fehler beim Löschen</returns>
        public override bool Delete(int id)
        {
            //Prüfen ob die übergebene UserGruppe auch keine Member hat und wenn ja, dann kann diese nicht mehr gelöscht werden.
            var memberCount = (from eUserGroup in CurrentHttpContext.GetDataModel().EFCategoryMenge.OfType<UserGroup>() where eUserGroup.ID == id && eUserGroup.EFUsers.Count() != 0 select eUserGroup.ID).Count();

            //Keine member gefunden, Gruppe kann entfernt werden
            if (memberCount == 0)
            {
                //Die passende UserGruppe heraussuchen und dann löschen
                UserGroup userGroup = (UserGroup) CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(id);
                if (userGroup != null)
                {
                    if (!userGroup.IsSystem)
                    {
                        CurrentHttpContext.GetDataModel().EFCategoryMenge.Remove(userGroup);
                        CurrentHttpContext.GetDataModel().SaveChanges();
                        CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.DeleteSuccessFullRESX, MessageTypes.ok);
                        return true;
                    }
                    else
                    {
                        //Fehler anzeigen das die Kategorie nicht gelöscht werden kann, da es sich um eine Systemgruppe handelt.
                        CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.SystemValuesCanNotBeDeletedRESX, MessageTypes.error);
                    }
                }
            }
            else
            {
                //Fehler anzeigen, das die Gruppe nicht gelöscht werden kann, da diese bereits verwendet wird.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserGroupInUserErrorRESX, MessageTypes.error);
            }

            return false;
        }

        /// <summary>
        /// Bearbeiten der übergebenen Kategorie Id
        /// </summary>
        /// <param name="id">Kategorie Id die bearbeitet werden soll</param>
        /// <returns>das passende Model mit den hinterlegten Daten aus der DB | Null bei einem Fehler</returns>
        public override CategoriesAddModel Edit(int id)
        {
            //Laden der übergebenen Kategorie
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(id);

            if (userGroup != null)
            {
                //Füllen des Modells mit den Daten und diese werden dann zurück gegeben und auf der Webseite angezeigt
                CategoriesAddModel categoriesAddModel = new CategoriesAddModel();
                categoriesAddModel.Name = userGroup.Name;
                categoriesAddModel.SortId = userGroup.SortId;
                return categoriesAddModel;
            }
            else
            {
                //Wenn ein Fehler beim Laden auftritt diesen anzeigen.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.LoadErrorRESX, MessageTypes.error);
            }

            return null;
        }

        /// <summary>
        /// Speichern der übergebenen Daten des geänderten Modells
        /// </summary>
        /// <param name="id">id die geändert werden soll</param>
        /// <param name="model">das Model mit den Daten die geändert werden sollen</param>
        /// <returns>TRUE->Änderung erfolgreich | FALSE->Daten konnten nicht geändert werden</returns>
        public override bool Edit(int id, CategoriesAddModel model)
        {
            //Laden der übergebenen Kategorie
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(id);

            if (userGroup != null)
            {
                //Füllen des Modells mit den Daten und diese werden dann zurück gegeben und auf der Webseite angezeigt
                userGroup.Name = model.Name;
                userGroup.SortId = model.SortId;
                CurrentHttpContext.GetDataModel().SaveChanges();

                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.SaveSuccessfullRESX, MessageTypes.ok);
                return true;
            }
            else
            {
                //Wenn ein Fehler beim Laden auftritt diesen anzeigen.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.LoadErrorRESX, MessageTypes.error);
            }

            return false;
        }

        /// <summary>
        /// Füllt das Model mit den Gruppen in denen sich der User befindet bzw. nicht befindet
        /// </summary>
        /// <param name="userId">UserId für die die Gruppen aufgelistet werden.</param>
        /// <returns>Ausgefülltes ViewModel</returns>
        public UserGroupsListModel UserGroupsByUser(int userId)
        {
            //Den User heraussuchen für den angezeigt werden soll in welchen Gruppen er ist.
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);
            //Inistialisieren des DatenModells und die ersten Werte setzten
            UserGroupsListModel userGroupsListModel = new UserGroupsListModel();
            userGroupsListModel.CurrentUser = efUser;

            //Setzten in welchen UserGroups sich der User befindet.
            userGroupsListModel.HasUserGroup = efUser.UserGroups.OrderByUrlParams();

            //Alle UserGroups heraussuchen die nicht im User enthalten sind, dafür müssen alle UserGroups durchgegangen werden und es muss geprüft werden ob der User in der Gruppe ist und nur die wo Count == 0 ist, ist der user nicht drin
            userGroupsListModel.HasNoUserGroup = (from eUserGroups in CurrentHttpContext.GetDataModel().EFCategoryMenge.OfType<UserGroup>() where eUserGroups.EFUsers.Where(p => p.ID == userId).Count() == 0 select eUserGroups).OrderByUrlParams();

            return userGroupsListModel;
        }

        /// <summary>
        /// Das Model für den View mit Daten füllen, es müssen alle User für die übergebene GroupId herausgesucht werden die in der Gruppe enthalten sind
        /// und alle die nicht enthalten sind.
        /// </summary>
        /// <param name="userGroupId">Die UserGroupId der die User zugeordnet werden sollen.</param>
        /// <returns>Das gefüllte ViewModel</returns>
        public UserGroupUsersListModel UsersByUserGroup(int userGroupId)
        {
            UserGroupUsersListModel userGroupUsersListModel = new UserGroupUsersListModel();
            //Die usergruppe heraussuchen und die UserListe zuweisen die in Ihr enthalten ist.
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(userGroupId);
            userGroupUsersListModel.UsersInGroup = userGroup.EFUsers.OrderByUrlParams();
            //Noch den Name für die aktuelle Usergruppe auslesen, das dieser auch auf der Oberfläche angezeigt werden kann
            userGroupUsersListModel.CurrentGroup = userGroup;

            //Alle User heraussuchen die nicht in der Gruppe enthalten sind, dafür müssen alle User durchgegangen werden und es muss geprüft werden wer in der Gruppe ist und nur die wo Count == 0 ist sind nicht in der Gruppe
            userGroupUsersListModel.UsersNotInGroup = (from efUser in CurrentHttpContext.GetDataModel().EFBaseMenge.OfType<EFUser>() where efUser.UserGroups.Where(p => p.ID == userGroupId).Count() == 0 select efUser).OrderByUrlParams();
            return userGroupUsersListModel;
        }

        /// <summary>
        /// Die übergebene UserId der übergebenen UserGruppe hinzufügen.
        /// </summary>
        /// <param name="userGroupId">Id der Usergruppe der die User Id hinzugefügt werden soll</param>
        /// <param name="userId">User Id die der UserGruppe hinzugefügt werden soll</param>
        /// <returns>TRUE->Hinzufügen erfolgreich | FALSE->Fehler beim Hinzufügen</returns>
        public bool AddUserToGroup(int userGroupId, int userId)
        {
            //Laden der Gruppe und des Users
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(userGroupId);
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);
            //Prüfen ob der User bereits mitglied in der Gruppe ist.
            if (!efUser.UserGroups.Contains(userGroup))
            {
                try
                {
                    //Den User zur Gruppe hinzufügen
                    efUser.UserGroups.Add(userGroup);
                    CurrentHttpContext.GetDataModel().SaveChanges();
                    CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserAddedSuccessfullyToListRESX, MessageTypes.ok);
                    return true;
                }
                catch (Exception)
                {
                    //Ein fehler beim Speichern, man soll es erneut versuchen.
                    CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.ErrorPleaseTryAgainRESX, MessageTypes.error);
                }
            }
            else
            {
                //Der User ist bereits Mitglied in der Gruppe warnung ausgeben
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserIsAllreadyInGroupRESX, MessageTypes.warning);
            }

            return false;
        }

        /// <summary>
        /// Die übergebene UserId der aus der UserGruppe entfernen.
        /// </summary>
        /// <param name="userGroupId">Id der Usergruppe aus der die User Id entfernt werden soll</param>
        /// <param name="userId">User Id die aus der UserGruppe gelöscht werden soll</param>
        /// <returns>TRUE->Entfernen erfolgreich | FALSE->Fehler beim Entfernen</returns>
        public bool DeleteUserFromGroup(int userGroupId, int userId)
        {
            //Laden der Gruppe und des Users
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(userGroupId);
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);
            //Prüfen ob der User mitglied in der Gruppe ist.
            if (efUser.UserGroups.Contains(userGroup))
            {
                try
                {
                    //Den user aus der Usergruppe entfernen
                    efUser.UserGroups.Remove(userGroup);
                    CurrentHttpContext.GetDataModel().SaveChanges();
                    CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserDeletedSuccessfullyFromListRESX, MessageTypes.ok);
                    return true;
                }
                catch (Exception)
                {
                    //Ein fehler beim Speichern, man soll es erneut versuchen.
                    CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.ErrorPleaseTryAgainRESX, MessageTypes.error);
                }
            }
            else
            {
                //Der User ist bereits Mitglied in der Gruppe warnung ausgeben
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserNotInGroupRESX, MessageTypes.warning);
            }

            return false;
        }

        /// <summary>
        /// Sucht die Gruppenrechte für die Usergruppe heraus die gesetzt sind bzw. nicht gesetzt sind und füllt das passende Model mit Daten
        /// </summary>
        /// <param name="groupId">Die Gruppe für die die Rechte herausgesucht werden sollen</param>
        /// <returns>Ausgefülltes ViewModel</returns>
        public GroupRightListModel RightsByUserGroup(int groupId)
        {
            //Erst einmal die Gruppe Laden, für die die Daten angezeigt werden sollen
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(groupId);
            //Initialisieren des Models
            GroupRightListModel groupRightListModel = new GroupRightListModel();
            groupRightListModel.CurrentGroup = userGroup;
            //Zuweisen der Rechte die der Gruppe bereits zugewiesen sind.
            groupRightListModel.HasUserRight = userGroup.UserRights.OrderByUrlParams();

            //Alle Rechte heraussuchen die nicht in der Gruppe enthalten sind, dafür müssen alle Rechte durchgegangen werden und es muss geprüft werden welches in der Gruppe ist und nur die wo Count == 0 ist sind nicht in der Gruppe
            groupRightListModel.HasNoUserRight = (from eUserRight in CurrentHttpContext.GetDataModel().EFCategoryMenge.OfType<UserRight>() where eUserRight.UserGroups.Where(p => p.ID == groupId).Count() == 0 select eUserRight).OrderByUrlParams();

            return groupRightListModel;
        }

        /// <summary>
        /// Hinzufügen des Rechts zur Gruppe
        /// </summary>
        /// <param name="rightId">RechteId die zur Gruppe hinzugefügt werden soll</param>
        /// <param name="groupId">Die Gruppe zu der das Recht hinzugefügt werden soll</param>
        /// <returns>TRUE->Erfolgreich hinzugefügt | FALSE->Fehler beim Hinzufügen</returns>
        public bool AddRightToGroup(int rightId, int groupId)
        {
            //Laden der beiden Objekte aus der DB
            UserRight userRight = (UserRight)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(rightId);
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(groupId);

            //Prüfen ob das Recht bereits der Gruppe hinzugefügt wurde
            if (!userGroup.UserRights.Contains(userRight))
            {
                //Das Recht der Gruppe hinzufügen
                userGroup.UserRights.Add(userRight);
                CurrentHttpContext.GetDataModel().SaveChanges();
                //Anzeigen das das Recht erfolgreich der Gruppe hinzugefügt wurde.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserRightAddedSuccessfullyToGroupRESX,MessageTypes.ok);
                return true;
            }
            else
            {
                //Fehlermeldung ausgeben, die angibt das das Recht nicht mehr der Gruppe zugewiesen ist.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.GroupAllreadyHasRightRESX,MessageTypes.warning);
            }

            return false;
        }

        /// <summary>
        /// Entfernen des Rechts von der Gruppe
        /// </summary>
        /// <param name="rightId">Das Recht was von der Gruppe entfernt werden soll</param>
        /// <param name="groupId">Die Gruppe von der das Recht entfernt werden soll</param>
        /// <returns>TRUE->Erfolgreich entfernt | FALSE->Fehler beim Entfernen der Rechte</returns>
        public bool DeleteRightFromGroup (int rightId, int groupId)
        {
            //Laden der beiden Objekte aus der DB
            UserRight userRight = (UserRight)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(rightId);
            UserGroup userGroup = (UserGroup)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(groupId);

            //Prüfen ob der Gruppe das Recht noch zugewiesen ist
            if (userGroup.UserRights.Contains(userRight))
            {
                //Der Gruppe das Recht entziehen
                userGroup.UserRights.Remove(userRight);
                CurrentHttpContext.GetDataModel().SaveChanges();
                //Meldunge anzeigen, das das Entfernen des Rechts erfolgreich war.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserRightDeletedSuccessfullyFromGroupRESX,MessageTypes.ok);
            }
            else
            {
                //Anzeigen das das Recht nicht mehr der Gruppe zugeordnet war.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserRightNotInGroupRESX,MessageTypes.warning);
            }

            return false;
        }
        #endregion
    }
}